<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
<script>
    // 向Set加入值的时候 不会发生类型转换 所以 5 和 "5" 是两个不同的值。
    // Set 内部判断两个值是否不同 使用的算法叫做 "Same-value-zero equality" , 它类似于精确相等运算符(===)
    // 主要的区别是 向Set加入值时认为 NaN 等于自身 而精确相等运算符认为NaN不等于自身

    let set = new Set();
    let a = NaN;
    let b = NaN;
    set.add(a);
    set.add(b);
    set // Set {NaN}

    // 两个对象总是不相等的
    let set = new Set();

    set.add({});
    set.size // 1

    set.add({});
    set.size // 2


    // Set实例的属性和方法
    // Set结构的实例有如下属性
    Set.prototype.constructor // 构造函数 默认就是Set函数
    Set.prototype.size // 返回set实例的成员总数

    // Set实例的方法分为两大类 操作方法 遍历方法
    Set.prototype.add(value) // 添加某个值 返回Set结构本身
    Set.prototype.delete(value) // 删除某个值 返回一个布尔值 表示删除是否成功
    Set.prototype.has(value) // 返回一个布尔值 表示该值是否为Set成员
    Set.prototype.clear() // 清除所有成员 没有返回值

    s.add(1).add(2).add(2);
    // 注意2被加入了两次

    s.size // 2

    s.has(1) // true
    s.has(2) // true
    s.has(3) // false

    s.delete(2);
    s.has(2) // false

    // 下面对比 Object 结构和 Set 结构
    // 对象的写法
    const properties = {
        'width': 1,
        'height': 1
    };

    if (properties[someName]) {
        // do something
    }

    // Set的写法
    const properties = new Set();

    properties.add('width');
    properties.add('height');

    if (properties.has(someName)) {
        // do something
    }


    // Array.from方法可以将Set结构转为数组
    const items = new Set([1, 2, 3, 4, 5]);
    const array = Array.from(items);

    // 去除数组重复成员的方法
    function dedupe(array) {
        return Array.from(new Set(array));
    }

    dedupe([1, 1, 2, 3]) // [1, 2, 3]


    // 遍历操作
    // Set结构的实例有4个遍历方法 可用于遍历成员
    Set.prototype.keys() // 返回键名的遍历器
    Set.prototype.values() // 返回键值的遍历器
    Set.prototype.entries() // 返回键值对的遍历器
    Set.prototype.forEach() // 使用回调函数遍历每个成员

    // 特别指出 Set遍历顺序就是插入顺序 这个特性有时非常有用 比如使用Set保存一个回调函数列表 调用时就能保证按照添加顺序调用

    // keys() values() entries()
    // 上述方法返回的都是遍历器对象(详见Iterator)
    // 由于Set结构没有键名 只有键值 (或者说键名和键值是同一个值) 所以keys()方法 和 values()方法 行为完全一致
    let set = new Set(['red', 'green', 'blue']);

    for (let item of set.keys()) {
        console.log(item);
    }
    // red
    // green
    // blue

    for (let item of set.values()) {
        console.log(item);
    }
    // red
    // green
    // blue

    for (let item of set.entries()) {
        console.log(item);
    }
    // ["red", "red"]
    // ["green", "green"]
    // ["blue", "blue"]


    // Set结构的实例默认可遍历
    // 它的遍历器生成函数默认就是它的value方法
    Set.prototype[Symbol.iterator] === Set.prototype.values // true

    // 意味着可以省略values方法 直接用for...of...循环遍历Set
    let set = new Set(['red', 'green', 'blue']);

    for (let x of set) {
        console.log(x);
    }
    // red
    // green
    // blue

    

</script>